#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

#include "../planificador_disco/lib_planificador.h"
#include "../planificador_disco/lib_planificador.c"

#include "fs_config.h"
#include "fs_fat.h"
#include "fs_cluster.h"
//#define DEBUG

void imprimo_resultados (union boot_sector , union FS_information_sector);
int hello_readdir(const char *, void *, fuse_fill_dir_t ,off_t , struct fuse_file_info *);

static const char *hello_str = "Hello World!\n";
static const char *hello_path = "/hello";

static int hello_getattr(const char *path, struct stat *stbuf)
{
    int res = 0;

    memset(stbuf, 0, sizeof(struct stat));
    if(strcmp(path, "/") == 0) {
        stbuf->st_mode = S_IFDIR | 0755;
        stbuf->st_nlink = 2;
    }
    else 	//if(strcmp(path, hello_path) == 0) {
    {
        stbuf->st_mode = S_IFREG | 0444;
        stbuf->st_nlink = 1;
        stbuf->st_size = strlen(hello_str);
    }
    /*else
        res = -ENOENT;*/

    return res;
}


/*static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,  off_t offset, struct fuse_file_info *fi)
{
    (void) offset;
    (void) fi;

    if(strcmp(path, "/") != 0)
        return -ENOENT;

    filler(buf, ".", NULL, 0);
    filler(buf, "..", NULL, 0);
    filler(buf, hello_path + 1, NULL, 0);

    return 0;
}*/


static int hello_open(const char *path, struct fuse_file_info *fi)
{
    if(strcmp(path, hello_path) != 0)
        return -ENOENT;

    if((fi->flags & 3) != O_RDONLY)
        return -EACCES;

    return 0;
}

static int hello_read(const char *path, char *buf, size_t size, off_t offset,struct fuse_file_info *fi)
{
    size_t len;
    (void) fi;
    if(strcmp(path, hello_path) != 0)
        return -ENOENT;

    len = strlen(hello_str);
    if (offset < len) {
        if (offset + size > len)
            size = len - offset;
        memcpy(buf, hello_str + offset, size);
    } else
        size = 0;

    return size;
}

static struct fuse_operations hello_oper = {
    .getattr	= hello_getattr,
    .readdir	= hello_readdir,
    .open	= hello_open,
    .read	= hello_read,
};

unsigned int *entrada_FAT;
unsigned long offset_sectores_de_datos;

int main(int argc, char *argv[])
{
  unsigned long nro_cluster;
  unsigned char *bloque_cluster;

  FILE *fp;

  union boot_sector v_boot_sector;
  union FS_information_sector v_FS_information_sector;

  //Abro el archivo FAT32
  if((fp = fopen(".//fat32.disk", "r+")) == NULL){
    printf("Imposible de abrir el archivo.\n");
    exit(1);
  }

  //Leo el primer cluster
  nro_cluster = 0;
  bloque_cluster=leer_un_cluster(nro_cluster, fp);

  //Lleno el boot_sector
  llenar_desde_cluster(&v_boot_sector.caracteres, bloque_cluster, 0 ,sizeof(v_boot_sector.caracteres));
  //Lleno el FS_information
  llenar_desde_cluster(&v_FS_information_sector.caracteres, bloque_cluster, (v_boot_sector.valores.value_sector_fs_information * SIZE_SECTOR) ,sizeof(v_FS_information_sector.caracteres));

  //Leo la tabla FAT32!
  entrada_FAT = llenar_Tabla_FAT (v_boot_sector, fp);
  //calculo la cantidad de clusters libres con la tabla
  unsigned long clusters_libres, largo_tabla_FAT;
  largo_tabla_FAT = largo_tabla_tabla_FAT_entero(v_boot_sector);
  clusters_libres = clusters_libres_en_FAT(entrada_FAT, largo_tabla_FAT);

  offset_sectores_de_datos = offset_sectores_para_datos(v_boot_sector);

  #ifdef DEBUG
  printf("Largo de la tabla FAT32 en memoria: %d", largo_tabla_FAT);
  for (int j=0;j<20;j++)
  {
  printf("\nLa entrada %d de la tabla FAT32 es... %x",j, entrada_FAT[j]);
  }
  printf("\nClusters libres: %d", clusters_libres);
  #endif

  //imprimo_resultados(v_boot_sector, v_FS_information_sector);

  eliminar_bloque_memoria(bloque_cluster);
  //cierro el archivo
  if( fclose( fp ))
	  printf("Error al cerrar el archivo.\n");
  return fuse_main(argc, argv, &hello_oper);
  //return 0;
}


void imprimo_resultados (union boot_sector  v_boot_sector, union FS_information_sector  v_FS_information_sector)
{
	  printf("\nLargo de Jump Instruction: %d", sizeof(v_boot_sector.caracteres.jump_instruction));
	  printf("\nJump Instruction: ");
	  imprimir_campo(v_boot_sector.caracteres.jump_instruction, sizeof(v_boot_sector.caracteres.jump_instruction));
	  printf("\nnombre: ");
	  imprimir_campo(v_boot_sector.caracteres.oem_name, sizeof(v_boot_sector.caracteres.oem_name));
	  printf("\nBytes por sector: ");
	  imprimir_campo(v_boot_sector.caracteres.bytes_per_sector, sizeof(v_boot_sector.caracteres.bytes_per_sector));
	  printf("\nSector por cluster: ");
	  imprimir_campo(v_boot_sector.caracteres.sector_per_cluster, sizeof(v_boot_sector.caracteres.sector_per_cluster));
	  printf("\nNintumero de FATs: ");
	  imprimir_campo(v_boot_sector.caracteres.number_of_fats, sizeof(v_boot_sector.caracteres.number_of_fats));
	  printf("\nCantidad de root dirs: ");
	  imprimir_campo(v_boot_sector.caracteres.number_of_root_dirs, sizeof(v_boot_sector.caracteres.number_of_root_dirs));
	  printf("\nSectores totales: ");
	  imprimir_campo(v_boot_sector.caracteres.total_sectors, sizeof(v_boot_sector.caracteres.total_sectors));
	  printf("\nMedia Descriptor: ");
	  imprimir_campo(v_boot_sector.caracteres.media_descriptor, sizeof(v_boot_sector.caracteres.media_descriptor));
	  printf("\nSectores por fat: ");
	  imprimir_campo(v_boot_sector.caracteres.sectors_per_fat, sizeof(v_boot_sector.caracteres.sectors_per_fat));
	  printf("\nSectores por track: ");
	  imprimir_campo(v_boot_sector.caracteres.sectors_per_track, sizeof(v_boot_sector.caracteres.sectors_per_track));
	  printf("\nNumero de cabezas: ");
	  imprimir_campo(v_boot_sector.caracteres.number_of_heads, sizeof(v_boot_sector.caracteres.number_of_heads));
	  printf("\nSectores ocultos: ");
	  imprimir_campo(v_boot_sector.caracteres.hidden_sectors_for_partition, sizeof(v_boot_sector.caracteres.hidden_sectors_for_partition));

	  printf("\nSectores totales2: ");
	  imprimir_campo(v_boot_sector.caracteres.total_sectors_greater, sizeof(v_boot_sector.caracteres.total_sectors_greater));
	  printf("\nSectores totales2: %d",v_boot_sector.valores.value_total_sectors_greater);
	  printf("\nBoot sector signature: ");
	  imprimir_campo(v_boot_sector.caracteres.boot_sector_signature, sizeof(v_boot_sector.caracteres.boot_sector_signature));

	  printf("\nSectores resevados: %d",v_boot_sector.valores.value_reserved_sector_count);
	  printf("\nBytes por sector: %d",v_boot_sector.valores.value_bytes_per_sector);
	  printf("\nSector de FS Information: %d",v_boot_sector.valores.value_sector_fs_information);
	  printf("\nNumber of free clusters: %d",v_FS_information_sector.valores.free_clusters);
	  printf("\nFS sector signature1: ");
	  imprimir_campo(v_FS_information_sector.caracteres.FS_infrmation_signature, sizeof(v_FS_information_sector.caracteres.FS_infrmation_signature));
	  printf("\nFS sector signature3: ");
	  imprimir_campo(v_FS_information_sector.caracteres.FS_infrmation_signature3, sizeof(v_FS_information_sector.caracteres.FS_infrmation_signature3));
}
